package com.yt.server;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import com.yt.server.api.IConnection;
import com.yt.server.api.IContext;
import com.yt.server.api.IGlobalScope;
import com.yt.server.api.IScope;
import com.yt.server.api.IScopeHandler;
import com.yt.server.api.StatisticsCounter;
import com.yt.server.api.event.IEvent;
import com.yt.server.api.event.IEventListener;
import com.yt.server.api.listeners.IConnectionListener;
import com.yt.server.api.listeners.IScopeListener;
import com.yt.server.comm.Connection;
import com.yt.server.exception.ScopeException;

/**
 * @author 刘晶
 * @描述 活动区/作用域（雏形）
 * @version 2013.9.22 一版
 */
public class Scope extends AttributeStore implements IScope {

	protected static Logger log = LoggerFactory.getLogger(Scope.class);

	/**
	 * ScopeNames迭代器
	 */
	static class PrefixFilteringStringIterator implements Iterator<String> {

		private final Iterator<String> iterator;

		private String next;

		private final String prefix;

		public PrefixFilteringStringIterator(Iterator<String> iterator,
				String prefix) {
			this.iterator = iterator;
			this.prefix = prefix;
		}

		public boolean hasNext() {
			if (next != null) {
				return true;
			}
			do {
				next = (iterator.hasNext()) ? iterator.next() : null;
			} while (next != null && !next.startsWith(prefix));
			return next != null;
		}

		public String next() {
			if (next != null) {
				final String result = next;
				next = null;
				return result.substring(prefix.length());
			}
			if (hasNext()) {
				return next();
			} else {
				return null;
			}
		}

		public void remove() {
			throw new UnsupportedOperationException();
		}
	}

	// 唯一识别,不能改变
	private String id;

	// 路径
	protected String path;

	// 名称
	protected String name;

	// 类型or用途
	protected String type;

	// 父节点
	protected IScope parent;

	// Scope控制权, null表示控制权例如公共大厅
	protected IConnection owner;

	// 注入的业务处理
	protected IScopeHandler handler;

	// 是否永久
	protected boolean persistent = false;

	// 数据深度
	protected long depth = UNSET;

	// 系统上下文
	protected IContext context = null;

	// 互斥锁
	protected Lock lock = new ReentrantLock(true);

	// Spring上下文
	protected ApplicationContext applicationContext;

	// notifier Thread数量
	private int notifierThreadPoolSize = 5;

	// 线程执行者
	protected static ExecutorService notifier = null;

	protected final StatisticsCounter subscopeStats = new StatisticsCounter();

	// 业务事件
	protected final Set<IEventListener> listeners = new HashSet<IEventListener>();

	protected final ConcurrentMap<String, IScope> children = new ConcurrentHashMap<String, IScope>();

	protected final Set<IScopeListener> scopeListeners = new CopyOnWriteArraySet<IScopeListener>();

	protected final Set<IConnectionListener> connectionListeners = new CopyOnWriteArraySet<IConnectionListener>();

	private final ConcurrentMap<String, IConnection> clientList = new ConcurrentHashMap<String, IConnection>(
			1);

	public Scope() {
	}

	public Scope(String name, String path) {
		this.name = name;
		this.path = path;
	}

	private Scope(Builder builder) {
		this.name = builder.name;
		this.parent = builder.parent;
		this.persistent = builder.persistent;
		this.type = builder.type == null ? TYPE : builder.type;
		this.path = this.parent.getPath() + "/" + this.name;
		if (null != builder.owner) {
			this.setOwner(builder.owner);
			this.join(owner);
		}
		notifier = Executors.newFixedThreadPool(notifierThreadPoolSize);
	}

	@Override
	public void setApplicationContext(ApplicationContext arg0)
			throws BeansException {
		this.applicationContext = arg0;
	}

	@Override
	public boolean hasChildScope(String name) {
		boolean has;
		lock();
		try {
			has = children.containsKey(TYPE + SEPARATOR + name);
		} finally {
			unlock();
		}
		return has;
	}

	/**
	 * 建立子节点
	 */
	@Override
	public boolean createChildScope(String name, String type,
			IConnection owner, boolean persistent) {
		final Scope scope = new Builder(this, name, type, owner, persistent)
				.build();
		return addChildScope(scope);
	}

	@Override
	public boolean addChildScope(IScope scope) {
		if (hasChildScope(scope.getName())) {
			return false;
		}
		String key = TYPE + SEPARATOR + scope.getName();
		if (children.get(key) == null) {
			children.putIfAbsent(key, scope);
			subscopeStats.increment();
			scope.setApplicationContext(applicationContext);
		}
		return true;
	}

	/**
	 * 移除子节点
	 */
	@Override
	public void removeChildScope(IScope scope) {
		lock();
		try {
			if (!persistent) {
				if (hasChildScope(scope.getName())) {
					children.remove(TYPE + SEPARATOR + scope.getName());
					subscopeStats.decrement();
					Collection<IScope> scopes = scope.getChildScopes();
					scopes.add(scope);
					Object[] scos = scopes.toArray();
					for (int i = 0; i < scos.length; i++) {
						IScope sco = (IScope) scos[i];
						Collection<IConnection> connections = sco
								.getConnections();
						for (IConnection conn : connections) {
							removeEventListener(conn);
							removeListener(conn.getConnectionListener());
							this.join(conn);
						}
					}
				}
			}
		} finally {
			unlock();
		}
	}

	@Override
	public void addEventListener(IEventListener listener) {
		this.listeners.add(listener);
	}

	@Override
	public void removeEventListener(IEventListener listener) {
		this.listeners.remove(listener);
	}

	@Override
	public Iterator<IEventListener> getEventListeners() {
		return this.listeners.iterator();
	}

	@Override
	public void dispatchEvent(IEvent event) {
		notifyEvent(event);
		notifyEvents(event);
	}

	@Override
	public boolean handleEvent(IEvent event) {
		// TODO Auto-generated method stub
		return false;
	}

	/**
	 * 当前作用于域广播
	 */
	@Override
	public void notifyEvent(IEvent event) {
		// TODO Auto-generated method stub
	}

	/**
	 * 当前作用区广播业务事件
	 */
	@Override
	public void notifyEvents(final IEvent event) {
		Runnable notification = new Runnable() {
			public void run() {
				for (IEventListener listener : listeners) {
					listener.notifyEvent(event);
				}
			}
		};
		notifier.execute(notification);
	}

	@Override
	public void setOwner(IConnection owner) {
		this.owner = owner;
	}

	@Override
	public IConnection getOwner() {
		return owner;
	}

	@Override
	public IScope getScope(String name) {
		return children.get(TYPE + SEPARATOR + name);
	}

	@Override
	public ClassLoader getClassLoader() {
		return null;
	}

	@Override
	public String getId() {
		return id;
	}

	@Override
	public String getType() {
		return type;
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public boolean hasParent() {
		return (parent != null);
	}

	@Override
	public void lock() {
		lock.lock();
	}

	@Override
	public void unlock() {
		lock.unlock();
	}

	@Override
	public String getPath() {
		return path;
	}

	@Override
	public IScope getParent() {
		return parent;
	}

	@Override
	public void setDepth(long depth) {
		this.depth = depth;
	}

	@Override
	public long getDepth() {
		if (depth == UNSET) {
			if (hasParent()) {
				depth = parent.getDepth() + 1;
			} else {
				depth = 0;
			}
		}
		return depth;
	}

	@Override
	public boolean hasHandler() {
		return (handler != null || (hasParent() && getParent().hasHandler()));
	}

	@Override
	public IScopeHandler getHandler() {
		if (handler != null) {
			return handler;
		} else if (hasParent()) {
			return getParent().getHandler();
		} else {
			return null;
		}
	}

	/**
	 * 获取所有父节点
	 */
	@Override
	public Collection<IScope> getParentScopes() {
		List<IScope> scopes = new ArrayList<IScope>();
		IScope parent = getParent();
		if (parent instanceof GlobalScope) {
			scopes.add(parent);
			return scopes;
		} else {
			scopes.add(parent);
			scopes.addAll(parent.getParentScopes());
		}
		return scopes;
	}

	/**
	 * 获取当前节点下的所有节点
	 */
	@Override
	public Collection<IScope> getChildScopes() {
		List<IScope> scopes = new ArrayList<IScope>();
		if (children.isEmpty()) {
			return scopes;
		} else {
			scopes.addAll(children.values());
			for (IScope iScope : children.values())
				scopes.addAll(iScope.getChildScopes());
		}
		return scopes;
	}

	/**
	 * 获取当前节点下的所有节点的所有连接
	 */
	@Override
	public Collection<IConnection> getChildScopeOfConnections() {
		List<IConnection> connections = new ArrayList<IConnection>();
		for (IScope scope : getChildScopes())
			connections.addAll(scope.getConnections());
		return connections;
	}

	@Override
	public Iterator<String> getScopeNames() {
		return new PrefixFilteringStringIterator(children.keySet().iterator(),
				TYPE + SEPARATOR);
	}

	@Override
	public Collection<IConnection> getConnections() {
		return clientList.values();
	}

	@Override
	public IContext getContext() {
		if (!hasContext() && hasParent()) {
			return parent.getContext();
		} else {
			return context;
		}
	}

	/**
	 * 加入Scope
	 */
	@Override
	public boolean join(IConnection conn) {
		if (!clientList.containsKey(conn.getClientId())) {
			if (this instanceof IGlobalScope
					|| (null != conn.getScope() && conn.getScope()
							.hasChildScope(name)) || this.owner == conn) {
				clientList.putIfAbsent(conn.getClientId(), conn);
				conn.setScope(this);
				addEventListener(conn);
				addListener(conn.getConnectionListener());
				System.out.println("成功加入: " + name);
				return true;
			} else
				throw new ScopeException(name + "不是"
						+ conn.getScope().getName() + "的子节点");
		}
		return false;
	}

	/**
	 * 离开Scope
	 */
	@Override
	public void leave(String clientId) {
		if (null != clientList.get(clientId)) {
			IConnection conn = clientList.remove(clientId);
			removeEventListener(conn);
			removeListener(conn.getConnectionListener());
			if (this.getClass() == GlobalScope.class && null == parent)
				conn.setScope(null);
			else
				parent.join(conn);
			System.out.println("成功离开: " + name);
		}
	}

	@Override
	public void addListener(IScopeListener listener) {
		this.scopeListeners.add(listener);
	}

	@Override
	public void addListener(IConnectionListener listener) {
		this.connectionListeners.add(listener);
	}

	@Override
	public void removeListener(IScopeListener listener) {
		this.scopeListeners.remove(listener);
	}

	@Override
	public void removeListener(IConnectionListener listener) {
		this.connectionListeners.remove(listener);
	}

	@Override
	public void notifyConnected(final IConnection conn) {
		Runnable notification = new Runnable() {
			public void run() {
				for (IConnectionListener listener : connectionListeners) {
					listener.notifyConnected(conn);
				}
			}
		};
		notifier.execute(notification);
	}

	@Override
	public void notifyDisconnected(final IConnection conn) {
		Runnable notification = new Runnable() {
			public void run() {
				for (IConnectionListener listener : connectionListeners) {
					listener.notifyDisconnected(conn);
				}
			}
		};
		notifier.execute(notification);
	}

	public void notifyScopeCreated(final IScope scope) {
		Runnable notification = new Runnable() {
			public void run() {
				for (IScopeListener listener : scopeListeners) {
					listener.notifyScopeCreated(scope);
				}
			}
		};
		notifier.execute(notification);
	}

	public void notifyScopeRemoved(final IScope scope) {
		Runnable notification = new Runnable() {
			public void run() {
				for (IScopeListener listener : scopeListeners) {
					listener.notifyScopeRemoved(scope);
				}
			}
		};
		notifier.execute(notification);
	}

	public boolean hasContext() {
		return context != null;
	}

	public int getActiveSubscopes() {
		return subscopeStats.getCurrent();
	}

	public int getMaxSubscopes() {
		return subscopeStats.getMax();
	}

	public int getTotalSubscopes() {
		return subscopeStats.getTotal();
	}

	public final static class Builder {
		private IScope parent;
		private String name;
		private String type;
		private IConnection owner;
		private boolean persistent;

		public Builder() {
		}

		public Builder(String name) {
			this.name = name;
		}

		public Builder(IScope parent, String name, String type,
				IConnection owner, boolean persistent) {
			this.name = name;
			this.type = type;
			this.parent = parent;
			this.owner = owner;
			this.persistent = persistent;
		}

		public Scope build() {
			return new Scope(this);
		}
	}

	public static void main(String[] args) {

		IConnection connection1 = new Connection();

		IConnection connection2 = new Connection();

		IConnection connection3 = new Connection();

		IConnection connection4 = new Connection();

		GlobalScope globalScope = new GlobalScope();
		globalScope.createChildScope("1", "game", connection1, false);
		globalScope.createChildScope("2", "game", connection4, false);

		// 创建1.1
		IScope scope = globalScope.getScope("1");
		scope.createChildScope("1.1", "game", connection2, false);

		// 创建1.1.1
		IScope scope1 = scope.getScope("1.1");
		scope1.createChildScope("1.1.1", "game", connection3, false);

		IScope scope2 = scope1.getScope("1.1.1");
		System.out.println("conn数" + globalScope.getConnections());
		System.out.println("allconn数"
				+ globalScope.getChildScopeOfConnections().size());
		System.out.println("scope数" + globalScope.getChildScopes());

		System.out.println("遍历连接路径:");
		Object[] os = globalScope.getChildScopeOfConnections().toArray();
		for (Object object : os) {
			System.out.println(((IConnection) object).getPath());
		}

		System.out.println("遍历Iscope路径");
		System.out.println("全局路径" + globalScope.getPath());
		for (IScope object : globalScope.getChildScopes()) {
			System.out.println(object.getPath());
		}
		globalScope.removeChildScope(scope);
		System.out
				.println("------------------------------------------------------");
		Object[] objects = globalScope.getConnections().toArray();
		System.out.println("conn数" + Arrays.toString(objects));
		System.out.println("allconn数"
				+ globalScope.getChildScopeOfConnections().size());
		System.out.println("scope数" + globalScope.getChildScopes());

		// System.out.println(objects[0].hashCode() + "" +
		// objects[1].hashCode());

		// path
		// System.out.println(scope2.getPath());
		// Context
		// System.out.println(scope2.getContext());

		// for (Iterator iterator = globalScope.getScopeNames(); iterator
		// .hasNext();) {
		// String type = (String) iterator.next();
		// System.out.println(type);
		// }
	}
}